package net.towee.client.com.dashboard.view;

import java.util.HashMap;
import java.util.Map;

import net.towee.client.com.dashboard.presenter.DashBoardPresenter.Display;
import net.towee.client.i18n.ToweeConstants;
import net.towee.client.resources.ClientResource;
import net.towee.client.widgets.DataHelpers;
import net.towee.model.account.Board;

import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.allen_sauer.gwt.dnd.client.drop.FlowPanelDropController;
import com.google.common.base.Preconditions;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasOpenHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;

public class DashBoardView extends FlowPanel implements Display {
	/**
	 * Board selector
	 * 
	 * @author c58
	 */
	private class BoardSelector extends FlowPanel implements HasOpenHandlers<Board>, ClickHandler {
		private Widget activeBoard;
		private Map<Board, Widget> boards = new HashMap<Board, Widget>();

		public BoardSelector() {
			// Set attribute for styling
			getElement().setAttribute("selector", "");
			
			// Create buttons
			createButtons();
		}

		private void createButtons() {
			FlowPanel buttons = new FlowPanel();
			buttons.getElement().setAttribute("buttons", "");
			buttons.add( editBoard );
			buttons.add( addBoard );
			buttons.add( addGadget );
			add(buttons);
			
			addGadget.setVisible(false);
			editBoard.setVisible(false);
		}

		public void addBoardItem(Board b) {
			Label item = new Label(DataHelpers.cutString(b.getName(), 33));
			item.setStyleName("");
			item.getElement().setAttribute("item", "");
			item.setLayoutData(b);
			item.addClickHandler(this);
			add(item);

			boards.put(b, item);
		}

		@Override
		public HandlerRegistration addOpenHandler(OpenHandler<Board> handler) {
			return addHandler(handler, OpenEvent.getType());
		}

		@Override
		public void onClick(ClickEvent event) {
			Widget w = (Widget) event.getSource();
			selectBoard((Board) w.getLayoutData());

			// Fire change event
			OpenEvent.fire(this, (Board) w.getLayoutData());
		}

		public void selectBoard(Board b) {
			// Change active board
			if (activeBoard != null)
				activeBoard.getElement().setAttribute("item", "");

			activeBoard = boards.get(b);
			activeBoard.getElement().setAttribute("item", "active");
			addGadget.setVisible(true);
			editBoard.setVisible(true);
		}
		
		public void removeBoard(Board b) {
			if(boards.containsKey(b)) {				
				boards.get(b).removeFromParent();
				boards.remove(b);
				
				Widget w = boards.get(b);
				if(activeBoard.equals( w ))
					activeBoard = null;
				
				if(boards.isEmpty()) {
					addGadget.setVisible(false);
					editBoard.setVisible(false);					
				}
			}
		}
	}

	/**
	 * Boards shower
	 * 
	 * @author c58
	 */
	private class BoardShower extends FlowPanel {
		private BoardItem activeBoard;
		private Map<Board, BoardItem> boards = new HashMap<Board, BoardItem>();

		public BoardShower() {
			getElement().setAttribute("shower", "");
		}

		public void addBoard(Board b) {
			BoardItem item = new BoardItem(b);
			this.boards.put(b, item);
		}

		public void showBoard(Board b) {
			Preconditions.checkArgument(boards.containsKey(b), "board not exists");

			// Remove active board
			if (activeBoard != null)
				activeBoard.removeFromParent();

			// Set current active board
			activeBoard = this.boards.get(b);
			add(activeBoard);
		}

		public HasWidgets getGadgetsContainer(Board b, int row, int cel) {
			Preconditions.checkArgument(boards.containsKey(b), "board not exists");
			return boards.get(b).getContainer(row, cel);
		}
		
		public void removeBoard(Board b) {
			if(boards.containsKey(b)) {				
				boards.get(b).removeFromParent();
				boards.remove(b);
				
				BoardItem w = boards.get(b);
				if(activeBoard.equals( w ))
					activeBoard = null;
			}
		}
	}

	/**
	 * Board item
	 * 
	 * @author c58
	 */
	private class BoardItem extends AbsolutePanel {
		private final Board board;
		private FlowPanel leftColumn = new FlowPanel();
		private FlowPanel rightColumn = new FlowPanel();
		private final Label noGadgets = new Label();

		public BoardItem(Board b) {
			this.board = b;
			getElement().setAttribute("board", "");
			leftColumn.getElement().setAttribute("left", "");
			rightColumn.getElement().setAttribute("right", "");
			
			// Create columns
			add(leftColumn);
			add(rightColumn);
			
			// Create drag'n'drop
			createDnD();
			
			// Create some words when board not contain
			// some gadgets
			if(board.getGadgets().isEmpty())
				createNoGadgets();
		}

		private void createNoGadgets() {
			noGadgets.getElement().setAttribute("nogadgets", "");
			noGadgets.setText( constants.noGadgets() );
			add(noGadgets);
		}

		private void createDnD() {
			PickupDragController widgetDragController = new PickupDragController(this, false);
		    widgetDragController.setBehaviorMultipleSelection(false);
		    getElement().getStyle().setOverflowX(Overflow.HIDDEN);
		    getElement().getStyle().setOverflowY(Overflow.AUTO);
		    
		    makeColumnDnD(widgetDragController, leftColumn);
		    makeColumnDnD(widgetDragController, rightColumn);			
		}

		private void makeColumnDnD(PickupDragController widgetDragController, FlowPanel column) {
			// initialize a widget drop controller for the current column
			FlowPanelDropController widgetDropController = new FlowPanelDropController( column );
		    widgetDragController.registerDropController( widgetDropController );

		    // Set widget drag controller
		    column.setLayoutData( widgetDragController );
		}

		public HasWidgets getContainer(int row, int cel) {
			if(cel > 2 || cel < 0)
				throw new IllegalArgumentException();
			
			// Remove noGadgets message
			noGadgets.removeFromParent();
			
			// Get column
			FlowPanel column = null;
			if(cel == 0)
				column = leftColumn;
			else
				column = rightColumn;
			
			// Return column
			return column;
		}

	}

	private final ToweeConstants constants;
	private final ClientResource resource;

	private final Button addGadget;
	private final Button addBoard;
	private final Button editBoard;

	private final BoardSelector selector;
	private final BoardShower shower;

	@Inject
	public DashBoardView(ToweeConstants constants, ClientResource resource) {
		this.constants = constants;
		this.resource = resource;

		this.addGadget = new Button( constants.dashAddGadget() );
		this.addBoard = new Button( constants.dashAddBoard() );
		this.editBoard = new Button( constants.dashEditBoard() );

		// Set style name
		this.setStyleName(resource.css().dashBoards());

		// Create board selector
		this.selector = new BoardSelector();
		add(selector);

		// Create shower
		this.shower = new BoardShower();
		add(shower);
	}

	@Override
	public void addBoard(Board b) {
		selector.addBoardItem(b);
		shower.addBoard(b);
	}

	@Override
	public void showBoard(Board b) {
		selector.selectBoard(b);
		shower.showBoard(b);
	}

	@Override
	public HasClickHandlers getAddGadgetButton() {
		return addGadget;
	}

	@Override
	public HasOpenHandlers<Board> getBoardOpenContainer() {
		return selector;
	}

	@Override
	public HasWidgets getGadgetsContainer(Board b, int row, int cel) {
		return shower.getGadgetsContainer(b, row, cel);
	}

	@Override
	public void removeBoard(Board board) {
		selector.removeBoard(board);
		shower.removeBoard(board);
	}

	@Override
	public void showFirstBoard() {
		if( !selector.boards.isEmpty() ) {
			Board b = selector.boards.keySet().iterator().next();
			showBoard( b );
		}
	}

	@Override
	public void onBoardLoading(Board b) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onBoardLoaded(Board b) {
		// TODO Auto-generated method stub

	}

	@Override
	public HasClickHandlers getAddBoardButton() {
		return addBoard;
	}

	@Override
	public HasClickHandlers getEditBoardButton() {
		return editBoard;
	}
}
